package org.zjvis.datascience.web.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.zjvis.datascience.common.annotation.ProjectAuth;
import org.zjvis.datascience.common.dto.DashboardDTO;
import org.zjvis.datascience.common.widget.dto.WidgetDTO;
import org.zjvis.datascience.common.enums.ProjectAuthEnum;
import org.zjvis.datascience.common.widget.enums.WidgetTypeEnum;
import org.zjvis.datascience.common.exception.DataScienceException;
import org.zjvis.datascience.common.model.ApiResult;
import org.zjvis.datascience.common.model.ApiResultCode;
import org.zjvis.datascience.common.util.CollectionUtil;
import org.zjvis.datascience.common.util.DozerUtil;
import org.zjvis.datascience.common.vo.DashboardVO;
import org.zjvis.datascience.service.DashboardService;
import org.zjvis.datascience.service.ProjectService;
import org.zjvis.datascience.service.UserProjectService;
import org.zjvis.datascience.service.WidgetService;

import javax.servlet.http.HttpServletRequest;
import java.util.Iterator;
import java.util.List;

/**
 * @description 仪表盘管理接口 Controller
 * @date 2021-12-01
 */
@Api(tags = "仪表盘管理")
@RestController
@RequestMapping("/dashboard")
public class DashboardController {

    @Autowired
    private DashboardService dashboardService;

    @Lazy
    @Autowired
    private WidgetService widgetService;

    @Autowired
    private UserProjectService userProjectService;

    @Autowired
    private ProjectService projectService;

    @PostMapping("/{publishNo}")
    @ApiOperation(value = "根据token查看已部署仪表盘")
    public ApiResult<DashboardVO> getID(@PathVariable("publishNo") String publishNo) {
        if (StringUtils.isEmpty(publishNo)) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        if (StringUtils.isEmpty(publishNo)) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        DashboardDTO dashboard = dashboardService.queryByPublishNo(publishNo);
        if (dashboard == null) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR, null, "查无此仪表盘");
        }
        DashboardVO ret = DozerUtil.mapper(dashboard, DashboardVO.class);
        ret.setPipelineId(projectService.getDefaultPipelineId(ret.getProjectId()));
        ret.setLayout(assembleLayout(dashboard.getLayout()));
        String publishLayout = dashboard.getPublishLayout();
        if (StringUtils.isNotEmpty(publishLayout)) {
            ret.setPublishLayout(assembleLayout(publishLayout, false));
        }
        return ApiResult.valueOf(ret);
    }

    @PostMapping("/trigger/{publishNo}")
    @ApiOperation(value = "根据token查看已部署仪表盘是否需要执行")
    public ApiResult<Boolean> trigger(@PathVariable("publishNo") String publishNo) throws InterruptedException {
        if (StringUtils.isEmpty(publishNo)) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        if (StringUtils.isEmpty(publishNo)) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        DashboardDTO dashboard = dashboardService.queryByPublishNo(publishNo);
        return ApiResult.valueOf(dashboardService.triggerIfNeed(dashboard));
    }


    @PostMapping("/queryByProjectId")
    @ApiOperation(value = "根据项目id获取仪表盘")
    public ApiResult<DashboardVO> queryByProjectId(HttpServletRequest request,
                                                   @ProjectAuth(auth = ProjectAuthEnum.READ) @RequestBody DashboardVO vo) {
        if (vo == null || vo.getProjectId() == null) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        DashboardDTO dashboard = dashboardService.queryByProjectId(vo.getProjectId());
        if (dashboard == null) {
            return ApiResult.valueOf(ApiResultCode.SUCCESS);
        }
        DashboardVO ret = DozerUtil.mapper(dashboard, DashboardVO.class);
        ret.setPipelineId(projectService.getDefaultPipelineId(vo.getProjectId()));
        ret.setLayout(assembleLayout(dashboard.getLayout()));
        return ApiResult.valueOf(ret);
    }

//    /**
//     * TODO可视化 构建允许多个仪表盘
//     *
//     * @param request
//     * @param vo
//     * @return
//     */
//    @PostMapping("/queryByProjectId")
//    @ApiOperation(value = "根据项目id获取仪表盘列表")
//    public ApiResult<List<DashboardVO>> queryByProjectId(HttpServletRequest request,
//                                                          @ProjectAuth(auth = ProjectAuthEnum.READ) @RequestBody DashboardVO vo) {
//        if (vo == null || vo.getProjectId() == null) {
//            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
//        }
//        List<DashboardDTO> dashboards = dashboardService.queryByProjectId2(vo.getProjectId());
//        if (dashboards == null) {
//            return ApiResult.valueOf(ApiResultCode.SUCCESS);
//        }
//        List<DashboardVO> result = dashboards.stream().map(dashboard -> {
//            DashboardVO dashboardVO = DozerUtil.mapper(dashboard, DashboardVO.class);
//            dashboardVO.setLayout(assembleLayout(dashboard.getLayout()));
//            return dashboardVO;
//        }).collect(Collectors.toList());
//        return ApiResult.valueOf(result);
//    }

    @PostMapping("/queryById")
    @ApiOperation(value = "根据id获取仪表盘")
    public ApiResult<DashboardVO> queryById(HttpServletRequest r, @RequestBody DashboardVO vo) {
        if (vo == null || vo.getId() == null) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        DashboardDTO dashboard = dashboardService.queryById(vo.getId());
        if (null != dashboard) {
            userProjectService.checkAuth(dashboard.getProjectId(), ProjectAuthEnum.READ.getValue());
        }
        DashboardVO ret = DozerUtil.mapper(dashboard, DashboardVO.class);
        ret.setLayout(assembleLayout(dashboard.getLayout()));
        return ApiResult.valueOf(ret);
    }

    @PostMapping(value = "/save")
    @ResponseBody
    @ApiOperation(value = "新增仪表盘", notes = "新增仪表盘")
    public ApiResult<Long> save(HttpServletRequest r, @RequestBody @ProjectAuth DashboardVO vo) {
        if (vo == null || vo.getProjectId() == null) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        DashboardDTO dashboard = vo.toDashboard();
        Long id = dashboardService.save(dashboard);
        return ApiResult.valueOf(id);
    }

    @PostMapping(value = "/update")
    @ResponseBody
    @ApiOperation(value = "更新仪表盘", notes = "更新仪表盘")
    public ApiResult<Long> update(HttpServletRequest r, @RequestBody @ProjectAuth DashboardVO vo) {
        if (vo == null || vo.getId() == null || vo.getProjectId() == null) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        DashboardDTO dashboard = vo.toDashboard();
        dashboardService.update(dashboard);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/deleteById")
    @ResponseBody
    @Transactional
    @ApiOperation(value = "删除仪表盘", notes = "删除仪表盘")
    public ApiResult<Long> deleteById(@RequestBody @ProjectAuth DashboardVO vo) {
        if (vo == null || vo.getId() == null) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }

        DashboardDTO exist = dashboardService.queryById(vo.getId());
        if (exist.getStatus() == 1) {
            return ApiResult.valueOf(ApiResultCode.SYS_ERROR, null, "该看板已发布不允许删除!");
        }
        String layout = exist.getLayout();
        if (StringUtils.isNotEmpty(layout)) {
            List<Long> deleteWidgetIds = Lists.newArrayList();
            JSONObject layoutJson = JSONObject.parseObject(layout);
            JSONArray gridItems = layoutJson.getJSONArray("gridItems");
            for (int i = 0; i < gridItems.size(); i++) {
                JSONObject widgetJson = gridItems.getJSONObject(i);
                Long widgetId = widgetJson.getLong("widgetId");
                deleteWidgetIds.add(widgetId);
            }
            widgetService.delete(null, deleteWidgetIds);
        }
        dashboardService.delete(vo.getId());
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/unstuck")
    @Transactional
    @ResponseBody
    @ApiOperation(value = "下架仪表盘", notes = "下架仪表盘")
    public ApiResult<Object> unstuck(@RequestBody @ProjectAuth DashboardVO vo) {
        try {
            dashboardService.unstuck(vo);
            return ApiResult.valueOf(true);
        } catch (DataScienceException e) {
            return ApiResult.error(ApiResultCode.DASHBOARD_UNSTUCK_FAILED, e.getMessage());
        }
    }

    @PostMapping(value = "/publish")
    @Transactional
    @ResponseBody
    @ApiOperation(value = "部署仪表盘", notes = "部署仪表盘")
    public ApiResult<String> publish(@RequestBody @ProjectAuth DashboardVO vo) {
        if (vo == null || vo.getId() == null) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        vo.setIsComplex(true);//每次都复制
        String publishNo = dashboardService.publish(vo);
        return ApiResult.valueOf(publishNo);
    }

    private String assembleLayout(String layout) {
        return assembleLayout(layout, true);
    }

    private String assembleLayout(String layout, Boolean needRemove) {
        JSONObject layoutJson = new JSONObject();
        if (StringUtils.isNoneEmpty(layout)) {
            layoutJson = JSONObject.parseObject(layout);
            JSONArray widgets = layoutJson.getJSONArray("gridItems");
            if (CollectionUtil.isNotEmpty(widgets)) {
                Iterator<Object> iterator = widgets.iterator();
                while (iterator.hasNext()) {
                    JSONObject widgetJson = (JSONObject) iterator.next();
                    //下面查不到widget就从dashboard展示中删除
                    Long widgetId = widgetJson.getLong("widgetId");
                    WidgetDTO widgetDTO = widgetService.queryById(widgetId);
                    if (null == widgetId || null == widgetDTO) {
                        if (needRemove) iterator.remove();
                        continue;
                    }
                    if (!widgetDTO.getType().equalsIgnoreCase(WidgetTypeEnum.TEXT.getDesc())) {
                        widgetJson.put("config", widgetDTO.getDataJson());
                    }
                }
                layoutJson.put("gridItems", widgets);
            }
        }
        return layoutJson.toJSONString();
    }

}
